
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>

#include "application.h"

#include "config/config.h"
#include "modbus/modbus_master.h"
#include "mqtt/mqtt_client.h"
#include "json/jsonTemplate.h"
#include "utils/BlockQueue.h"
#include "utils/timer.h"
#include "log/syslog.h"

#define TAG "Application"

using namespace std;
using namespace equip_system;

std::atomic<bool> running(true);

std::mutex data_mutex;
// ModbusData modbus_data;

#define MODBUS_ERROR_CODES "errorcodes.ini"
#define MQTT_CONFIG_FILE "data/nodeconfig_mqtt.json"
#define MODBUS_CONFIG_FILE "data/nodeconfig_modbus.json"
#define MODBUS_DATA_CONFIG_FILE "data/dataconfig_modbus.json"

/*
创建配置管理器
*/
// JsonHandler json_handler;
JsonTemplate<MqttConfig, CMqttConfig> hMqttConfig;
JsonTemplate<ModbusConfig, CModbusCofing> hModbusConfig;
JsonTemplate<NodeData_Config, CNodeDataCofing> hModbusdataConfig;

// EquipDevice equip_data;
NodeData_Config equip_config;
/*

*/
const size_t QUEUE_CAPACITY = 5;                                 // 队列容量
BlockingQueue<NodeData_Config> core_data_queue_(QUEUE_CAPACITY); // 核心数据缓存

/*
资料；https://spotpear.cn/wiki/ESP32-S3R8-PoE-ETH-RJ45-Camera-Micro-SD-Pico-W5500-OV2640-OV5640.html
*/
Application::Application()
{
}

Application::~Application()
{
}

// 定时读取Modbus数据的线程
void modbus_thread()
{
    std::vector<EquipProperty> _old_param;

    // 获取Modbus配置
    ModbusConfig _Config;
    if (!hModbusConfig.read(MODBUS_CONFIG_FILE, _Config))
    {
        ES_LOG(TAG, LEVEL_ERROR, "Failed to load configuration, exiting...");
        return;
    }
    int RECONNECT_DELAY_MS = (_Config.retry_delay == 0 ? 5000 : _Config.retry_delay); // 重连延迟（毫秒）

    // 获取数据配置
    LPGETDATA _getdata_funtion = nullptr; //modbus_node_callback;

    // create modbus_master
    ModbusMaster modbus_node(_Config.server_ip, _Config.server_port, _getdata_funtion, nullptr);

    // 启动时加载错误码配置
    if (!modbus_node.loadErrorCodes(MODBUS_ERROR_CODES))
    {
        ES_LOG(TAG, LEVEL_ERROR, "Failed to load error codes configuration!");
        // 处理加载失败的情况
    }

    // 2. 外层循环：持续重试连接（直到程序退出）
    while (running)
    {
        // 3. 尝试初始化并启动ModbusMaster
        if (!modbus_node.Start())
        {
            string _infor("Modbus-Node Start() failed, will retry after " + to_string(RECONNECT_DELAY_MS) + "ms");
            ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
            this_thread::sleep_for(chrono::milliseconds(RECONNECT_DELAY_MS));
            continue; // 重试Start()
        }

        // 4. 尝试连接到从站
        if (!modbus_node.Run())
        {
            string _infor("Modbus-Node Run() failed, will retry after " + to_string(RECONNECT_DELAY_MS) + "ms");
            ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
            modbus_node.Stop(); // 清理资源
            this_thread::sleep_for(chrono::milliseconds(RECONNECT_DELAY_MS));
            continue; // 重试连接
        }

        // 5. 连接成功：进入数据读取循环
        ES_LOG(TAG, LEVEL_INFO, "Modbus-Node connected successfully, start reading data");
        while (running && modbus_node.isConnected())
        {
            NodeData_Config _data;
            memset(&_data, 0, sizeof(equip_config));
            _data = equip_config;
            int read_success = modbus_node.readData(_data);

            if (read_success < 0 || _data.list.size() <= 0)
            {
                ES_LOG(TAG, LEVEL_WARNING, "Modbus-Node read data failed(%d), check connection", read_success);
                break;
            }
            else
            {
                bool _bnew = false;

                // 首次读取：_old_param为空，直接判定为新数据
                if (_old_param.empty())
                {
                    _bnew = true;
                }
                else
                {
                    // 检查元素数量是否变化
                    if (_data.list.size() != _old_param.size())
                    {
                        _bnew = true;
                    }
                    else
                    {
                        // 逐元素比较value
                        auto it1 = _old_param.begin();
                        for (auto it = _data.list.begin(); it != _data.list.end(); ++it, ++it1)
                        {
                            if (it->value != it1->value)
                            { // 完整比较value数组
                                _bnew = true;
                                break;
                            }
                        }
                    }
                }

                if (_bnew)
                {
                    core_data_queue_.push(_data); // 数据变化：推入队列
                    _old_param = _data.list;      // 更新旧数据基准
                    ES_LOG(TAG, LEVEL_INFO, "Modbus-Node read new data, pushed to queue");
                }
                else
                {
                    ES_LOG(TAG, LEVEL_WARNING, "Modbus-Node data unchanged, skipped ...");
                }

                this_thread::sleep_for(chrono::milliseconds(_Config.cycle_delay < 10 ? 10 : _Config.cycle_delay));
            }
        }

        // 6. 连接断开：清理资源并准备重试
        ES_LOG(TAG, LEVEL_ERROR, "Modbus-Node disconnected, preparing to reconnect");
        modbus_node.Stop();                                               // 确保资源释放
        this_thread::sleep_for(chrono::milliseconds(RECONNECT_DELAY_MS)); // 重连延迟
    }

    // 7. 程序退出：最终清理
    modbus_node.Stop();
    ES_LOG(TAG, LEVEL_INFO, "Modbus thread exited");
}

/*
 *   定时发布MQTT消息的线程
**/
void mqtt_thread()
{
    long _work_order = 0;
    /*
        加载配置文件--网络配置
     */
    // JsonTemplate<NODE_CONFIG, CModbusCofing> hNodeConfig;
    MqttConfig _config;
    if (!hMqttConfig.read(MQTT_CONFIG_FILE, _config))
    {
        ES_LOG(TAG, LEVEL_ERROR, "Failed to load configuration, exiting...");
        return;
    }
    int MQTT_RECONNECT_DELAY_MS = (_config.retry_delay == 0 ? 5000 : _config.retry_delay); // MQTT重连延迟（毫秒）

    // 创建MQTT客户端
    MqttClient client;

    // 外层循环：持续重试连接
    while (running)
    {
        // 尝试连接MQTT服务器
        if (!client.connect(_config))
        {
            string _infor("MQTT connection failed, will retry after " + to_string(MQTT_RECONNECT_DELAY_MS) + "ms");
            ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
            this_thread::sleep_for(chrono::milliseconds(MQTT_RECONNECT_DELAY_MS));
            continue; // 重试连接
        }

        ES_LOG(TAG, LEVEL_INFO, "MQTT connected successfully");

        // 内层循环：处理数据发布（直到断开或程序退出）
        while (running && client.isConnected())
        {
            // 检查缓存队列中是否有数据
            size_t _num = core_data_queue_.size();
            if (_num > 0)
            {
                for (int i = 0; i < _num; i++)
                {
                    //从缓存队列中逐个提取数据
                    NodeData_Config _data = core_data_queue_.pop();

                    // NodeData_Config --> json-string
                    vector<string> _param;
                    _param.clear();
                    _param.push_back(to_string(_work_order++));
                    string json_data = hModbusdataConfig.serialize(_data, _param);

                    // 发布到MQTT broker（检查发布结果）
                    bool publish_success = client.publish(_config.topic, json_data);
                    if (publish_success)
                    {
                        string _infor;
                        char _id[10] = {0};
                        memset(_id, 0, sizeof(char) * 10);
                        sprintf(_id, "[%d] ", i + 1);
                        _infor.append(_id);
                        _infor.append(json_data);
                        ES_LOG(TAG, LEVEL_INFO, _infor.c_str());
                    }
                    else
                    {
                        ES_LOG(TAG, LEVEL_WARNING, "MQTT publish failed, check connection");
                        break; // 跳出循环，准备重连
                    }
                }
            }

            this_thread::sleep_for(chrono::milliseconds(_config.cycle_delay < 10 ? 10 : _config.cycle_delay)); // 检查间隔
        }

        // 连接断开：清理并准备重连
        ES_LOG(TAG, LEVEL_ERROR, "MQTT disconnected, preparing to reconnect");
        client.disconnect(); // 确保资源释放
        this_thread::sleep_for(chrono::milliseconds(MQTT_RECONNECT_DELAY_MS));
    }

    // 程序退出：最终清理
    client.disconnect();
    ES_LOG(TAG, LEVEL_INFO, "MQTT thread exited");
}

/*
*/
int Application::Start()
{
    /*
        加载配置文件--PLC数据源
     */
    if (!hModbusdataConfig.read(MODBUS_DATA_CONFIG_FILE, equip_config))
    {
        ES_LOG(TAG, LEVEL_ERROR, "Failed to load configuration, exiting...");
        return -1;
    }

    /*
     */
    thread modbus_t(modbus_thread);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    thread mqtt_t(mqtt_thread);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    /*
     */
    string _infor = "Press Enter to exit...";
    ES_LOG(TAG, LEVEL_INFO, _infor.c_str());
    // syslog.print(_infor.c_str());
    cin.get(); // 阻塞等待回车

    running = false; // 通知线程退出
    /*
     */
    // 回收线程
    modbus_t.join();
    mqtt_t.join();

    return 0;
}
